package com.atguigu.gulimall.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.gulimall.common.constant.ProductConstant;
import com.atguigu.gulimall.common.to.SkuReductionTo;
import com.atguigu.gulimall.common.to.SpuBoundTo;
import com.atguigu.gulimall.common.to.es.SkuEsModel;
import com.atguigu.gulimall.common.utils.PageUtils;
import com.atguigu.gulimall.common.utils.Query;
import com.atguigu.gulimall.common.utils.R;
import com.atguigu.gulimall.product.dao.SpuInfoDao;
import com.atguigu.gulimall.product.entity.*;
import com.atguigu.gulimall.product.feign.CouponFeignService;
import com.atguigu.gulimall.product.feign.SearchFeignService;
import com.atguigu.gulimall.product.feign.WareFeignService;
import com.atguigu.gulimall.product.service.*;
import com.atguigu.gulimall.product.vo.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {


    @Autowired
    private SpuInfoDescService spuInfoDescService;

    @Autowired
    private SpuImagesService spuImagesService;

    @Autowired
    private AttrService attrService;

    @Autowired
    private ProductAttrValueService attrValueService;

    @Autowired
    private SkuInfoService skuInfoService;

    @Autowired
    private SkuImagesService skuImagesService;

    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    private CouponFeignService couponFeignService;

    @Autowired
    private WareFeignService wareFeignService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SearchFeignService searchFeignService;



    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    @Transactional
    @Override
    public void saveSpuInfo(SpuSaveVo vo) {
        // 1. 保存SPU基本信息 pms_spu_info
        SpuInfoEntity spuInfo = new SpuInfoEntity();
        BeanUtils.copyProperties(vo, spuInfo);
        spuInfo.setCreateTime(new Date());
        spuInfo.setUpdateTime(new Date());
        this.saveBaseSpuInfo(spuInfo);

        // 2. 保存SPU的描述图片： pms_spu_info_desc  descripte
        List<String> descriptList = vo.getDecript();
        Long spuId = spuInfo.getId();
        SpuInfoDescEntity descriptEntity = new SpuInfoDescEntity();
        descriptEntity.setSpuId(spuId);
        descriptEntity.setDecript(String.join(",", descriptList));
        spuInfoDescService.saveSpuInfoDesc(descriptEntity);

        // 3. 保存spu的图片集: pms_spu_images
        List<String> images = vo.getImages();
        spuImagesService.saveSpuImages(spuId, images);


        // 4. 保存spu的规格参数： pms_product_attr_value
        List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
        if (baseAttrs != null && baseAttrs.size() > 0){
            List<ProductAttrValueEntity> list = baseAttrs.stream().map(attr -> {
                ProductAttrValueEntity attrValueEntity = new ProductAttrValueEntity();
                attrValueEntity.setAttrId(attr.getAttrId());
                attrValueEntity.setAttrValue(attr.getAttrValues());
                attrValueEntity.setQuickShow(attr.getShowDesc());
                attrValueEntity.setSpuId(spuId);

                AttrEntity attrEntity = attrService.getById(attr.getAttrId());
                attrValueEntity.setAttrName(attrEntity.getAttrName());
                return attrValueEntity;
            }).collect(Collectors.toList());
            attrValueService.saveProductAttr(list);
        }


        // 5. 保存spu的积分信息： gulimall_sms -> sms_spu_bounds
        Bounds bounds = vo.getBounds();
        SpuBoundTo to = new SpuBoundTo();
        BeanUtils.copyProperties(bounds, to);
        to.setSpuId(spuId);
        couponFeignService.saveSpuBounds(to);

        // 6. 保存当前spu对应的所有sku信息
        List<Skus> skuList = vo.getSkus();
        if (skuList != null && skuList.size() > 0){
            for (Skus sku : skuList) {
                List<Images> skuImages = sku.getImages();
                String defaultImage = "";
                for (Images skuImage : skuImages) {
                    if (skuImage.getDefaultImg() == 1){
                        defaultImage = skuImage.getImgUrl();
                    }
                }

                // 6.1 sku基本信息： pms_sku_info
                SkuInfoEntity skuInfo = new SkuInfoEntity();
                BeanUtils.copyProperties(sku, skuInfo);
                skuInfo.setBrandId(spuInfo.getBrandId());
                skuInfo.setCatalogId(spuInfo.getCatalogId());
                skuInfo.setSaleCount(0l);
                skuInfo.setSpuId(spuId);
                skuInfo.setSkuDefaultImg(defaultImage);
                skuInfoService.saveSkuInfo(skuInfo);

                Long skuId = skuInfo.getSkuId();

                // 6.2 sku图片信息： pms_sku_images
                List<Images> skuImagesList = sku.getImages();
                if (skuImagesList != null && skuImagesList.size() > 0){
                    List<SkuImagesEntity> list = skuImagesList.stream().map(image -> {
                        SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                        skuImagesEntity.setSkuId(skuId);
                        skuImagesEntity.setDefaultImg(image.getDefaultImg());
                        skuImagesEntity.setImgUrl(image.getImgUrl());
                        return skuImagesEntity;
                    }).filter(entity -> {
                        return StringUtils.isNotBlank(entity.getImgUrl());
                    }).collect(Collectors.toList());
                    skuImagesService.saveBatch(list);
                }

                // 6.3 sku的销售属性信息：pms_sku_sale_attr_value
                List<Attr> skuAttrList = sku.getAttr();
                if (skuAttrList != null && skuAttrList.size() > 0){
                    List<SkuSaleAttrValueEntity> list = skuAttrList.stream().map(attr -> {
                        SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                        BeanUtils.copyProperties(attr, skuSaleAttrValueEntity);
                        skuSaleAttrValueEntity.setSkuId(skuId);
                        return skuSaleAttrValueEntity;
                    }).collect(Collectors.toList());
                    skuSaleAttrValueService.saveBatch(list);
                }

                // 6.4 sku的优惠满减信息： gulimall_sms -> sms_sku_ladder/sms_sku_full_reduction/sms_member_price
                SkuReductionTo reductionTo = new SkuReductionTo();
                BeanUtils.copyProperties(sku, reductionTo);
                reductionTo.setSkuId(skuId);
                if (reductionTo.getFullCount() > 0 || reductionTo.getFullPrice().compareTo(new BigDecimal(0)) > 0){
                    R r = couponFeignService.saveSkuReduction(reductionTo);
                    if (r.getCode() != 0){
                        log.error("远程保存sku优惠满减信息失败...");
                    }
                }
            }
        }


    }

    @Override
    public void saveBaseSpuInfo(SpuInfoEntity spuInfo) {
        this.baseMapper.insert(spuInfo);
    }


    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<SpuInfoEntity>();
        String key = (String) params.get("key");
        if (StringUtils.isNotBlank(key)){
            wrapper.and( w -> {
                w.eq("id", key).or().like("spu_name", key);
            } );
        }
        String status = (String) params.get("status");
        if (StringUtils.isNotBlank(status)){
            wrapper.eq("publish_status", status);
        }

        String brandId = (String) params.get("brandId");
        if (StringUtils.isNotBlank(brandId) && !"0".equals(brandId)){
            wrapper.eq("brand_id", brandId);
        }
        String catelogId = (String) params.get("catelogId");
        if (StringUtils.isNotBlank(catelogId) && !"0".equalsIgnoreCase(catelogId)){
            wrapper.eq("catalog_id", catelogId);
        }
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }

    @Override
    public void up(Long spuId) {
        // 查询当前spuId 对应的sku信息
        List<SkuInfoEntity> skus = skuInfoService.getSkusBySpuId(spuId);

        // 4. 查询当前spu对应的sku里面所有可以被用来检索的规格属性
        // 4.1 spu对应sku下所有的属性
        List<ProductAttrValueEntity> attrs = attrValueService.baseListForSpu(spuId);
        // 4.2 所有属性的Id
        List<Long> attrIds = attrs.stream().map(ProductAttrValueEntity::getAttrId).collect(Collectors.toList());
        // 4.3 所有可以用来检索的属性
        List<Long> searchAttrIds = attrService.selectSearchAttrIds(attrIds);
        // 4.4 去重
        Set<Long> idSet = new HashSet<>(searchAttrIds);
        List<SkuEsModel.Attrs> esModalAttrs = attrs.stream().filter(item -> {
            return idSet.contains(item.getAttrId());
        }).map(item -> {
            SkuEsModel.Attrs attr = new SkuEsModel.Attrs();
            BeanUtils.copyProperties(item, attr);
            return attr;
        }).collect(Collectors.toList());

        // 1. 远程调用 库存系统是否有库存
        List<Long> skuIds = skus.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
        Map<Long, Boolean> hasStockMap = null;
        try {
            R skuHasStock = wareFeignService.getSkuHasStock(skuIds);
            List<SkuHasStockVo> data = JSON.parseObject(JSON.toJSONString(skuHasStock.get("data")), new TypeReference<List<SkuHasStockVo>>() {
            });
            hasStockMap = data.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
        }catch (Exception e){
            log.error("库存服务查询异常：原因{}", e);
        }

        Map<Long, Boolean> stockMap = hasStockMap;
        List<SkuEsModel> list = skus.stream().map(sku -> {
            SkuEsModel esModel = new SkuEsModel();
            BeanUtils.copyProperties(sku, esModel);
            esModel.setSkuPrice(sku.getPrice());
            esModel.setSkuImg(sku.getSkuDefaultImg());
            // 1. 远程调用 库存系统是否有库存
            if (stockMap == null || stockMap.size() == 0 ){
                esModel.setHasStock(true); // 默认有库存
            }else {
                esModel.setHasStock(stockMap.get(sku.getSkuId()));
            }
            // 2. 热度评分
            esModel.setHotScore(0l);
            // 3. 查询品牌和分类的名字信息
            BrandEntity brandEntity = brandService.getById(sku.getBrandId());
            esModel.setBrandName(brandEntity.getName());
            esModel.setBrandImg(brandEntity.getLogo());
            // 4. 查询商品分类的名字
            CategoryEntity categoryEntity = categoryService.getById(sku.getCatalogId());
            esModel.setCatalogName(categoryEntity.getName());
            // 4. 设置检索属性
            esModel.setAttrs(esModalAttrs);
            // 5. 将数据发送给es进行保存， gulimall-search
            return esModel;
        }).collect(Collectors.toList());

        // 5. 将数据发送给es进行保存， gulimall-search
        R r = searchFeignService.productStatusUp(list);
        if (r.getCode() == 0){
            // 远程调用成功， 修改当前spu得状态
            baseMapper.updateSpuStatus(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());
        }else {
            // 远程调用失败， 重复调用， 接口幂等性
        }
    }


    @Override
    public SpuInfoEntity getSpuInfoBySkuId(Long skuId) {
        SkuInfoEntity skuInfo = skuInfoService.getById(skuId);
        Long spuId = skuInfo.getSpuId();
        SpuInfoEntity spuInfo = getById(spuId);
        return spuInfo;
    }
}